home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / test / test_optparse.py < prev    next >
Text File  |  2005-10-18  |  57KB  |  1,501 lines

  1. #!/usr/bin/python
  2.  
  3. #
  4. # Test suite for Optik.  Supplied by Johannes Gijsbers
  5. # (taradino@softhome.net) -- translated from the original Optik
  6. # test suite to this PyUnit-based version.
  7. #
  8. # $Id: test_optparse.py,v 1.10 2004/10/27 02:43:25 tim_one Exp $
  9. #
  10.  
  11. import sys
  12. import os
  13. import copy
  14. import unittest
  15.  
  16. from cStringIO import StringIO
  17. from pprint import pprint
  18. from test import test_support
  19.  
  20. from optparse import make_option, Option, IndentedHelpFormatter, \
  21.      TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, \
  22.      SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, \
  23.      BadOptionError, OptionValueError, Values, _match_abbrev
  24.  
  25. # Do the right thing with boolean values for all known Python versions.
  26. try:
  27.     True, False
  28. except NameError:
  29.     (True, False) = (1, 0)
  30.  
  31.  
  32. class InterceptedError(Exception):
  33.     def __init__(self,
  34.                  error_message=None,
  35.                  exit_status=None,
  36.                  exit_message=None):
  37.         self.error_message = error_message
  38.         self.exit_status = exit_status
  39.         self.exit_message = exit_message
  40.  
  41.     def __str__(self):
  42.         return self.error_message or self.exit_message or "intercepted error"
  43.  
  44. class InterceptingOptionParser(OptionParser):
  45.     def exit(self, status=0, msg=None):
  46.         raise InterceptedError(exit_status=status, exit_message=msg)
  47.  
  48.     def error(self, msg):
  49.         raise InterceptedError(error_message=msg)
  50.  
  51.  
  52. class BaseTest(unittest.TestCase):
  53.     def assertParseOK(self, args, expected_opts, expected_positional_args):
  54.         """Assert the options are what we expected when parsing arguments.
  55.  
  56.         Otherwise, fail with a nicely formatted message.
  57.  
  58.         Keyword arguments:
  59.         args -- A list of arguments to parse with OptionParser.
  60.         expected_opts -- The options expected.
  61.         expected_positional_args -- The positional arguments expected.
  62.  
  63.         Returns the options and positional args for further testing.
  64.         """
  65.  
  66.         (options, positional_args) = self.parser.parse_args(args)
  67.         optdict = vars(options)
  68.  
  69.         self.assertEqual(optdict, expected_opts,
  70.                          """
  71. Options are %(optdict)s.
  72. Should be %(expected_opts)s.
  73. Args were %(args)s.""" % locals())
  74.  
  75.         self.assertEqual(positional_args, expected_positional_args,
  76.                          """
  77. Positional arguments are %(positional_args)s.
  78. Should be %(expected_positional_args)s.
  79. Args were %(args)s.""" % locals ())
  80.  
  81.         return (options, positional_args)
  82.  
  83.     def assertRaises(self,
  84.                      func,
  85.                      args,
  86.                      kwargs,
  87.                      expected_exception,
  88.                      expected_message):
  89.         """
  90.         Assert that the expected exception is raised when calling a
  91.         function, and that the right error message is included with
  92.         that exception.
  93.  
  94.         Arguments:
  95.           func -- the function to call
  96.           args -- positional arguments to `func`
  97.           kwargs -- keyword arguments to `func`
  98.           expected_exception -- exception that should be raised
  99.           expected_output -- output we expect to see
  100.  
  101.         Returns the exception raised for further testing.
  102.         """
  103.         if args is None:
  104.             args = ()
  105.         if kwargs is None:
  106.             kwargs = {}
  107.  
  108.         try:
  109.             func(*args, **kwargs)
  110.         except expected_exception, err:
  111.             actual_message = str(err)
  112.             self.assertEqual(actual_message,
  113.                              expected_message,
  114.                              """\
  115. expected exception message:
  116. '''%(expected_message)s'''
  117. actual exception message:
  118. '''%(actual_message)s'''
  119. """ % locals())
  120.  
  121.             return err
  122.         else:
  123.             self.fail("""expected exception %(expected_exception)s not raised
  124. called %(func)r
  125. with args %(args)r
  126. and kwargs %(kwargs)r
  127. """ % locals ())
  128.  
  129.  
  130.     # -- Assertions used in more than one class --------------------
  131.  
  132.     def assertParseFail(self, cmdline_args, expected_output):
  133.         """
  134.         Assert the parser fails with the expected message.  Caller
  135.         must ensure that self.parser is an InterceptingOptionParser.
  136.         """
  137.         try:
  138.             self.parser.parse_args(cmdline_args)
  139.         except InterceptedError, err:
  140.             self.assertEqual(err.error_message, expected_output)
  141.         else:
  142.             self.assertFalse("expected parse failure")
  143.  
  144.     def assertOutput(self,
  145.                      cmdline_args,
  146.                      expected_output,
  147.                      expected_status=0,
  148.                      expected_error=None):
  149.         """Assert the parser prints the expected output on stdout."""
  150.         save_stdout = sys.stdout
  151.         try:
  152.             try:
  153.                 sys.stdout = StringIO()
  154.                 self.parser.parse_args(cmdline_args)
  155.             finally:
  156.                 output = sys.stdout.getvalue()
  157.                 sys.stdout = save_stdout
  158.  
  159.         except InterceptedError, err:
  160.             self.assertEqual(output, expected_output)
  161.             self.assertEqual(err.exit_status, expected_status)
  162.             self.assertEqual(err.exit_message, expected_error)
  163.         else:
  164.             self.assertFalse("expected parser.exit()")
  165.  
  166.     def assertTypeError(self, func, expected_message, *args):
  167.         """Assert that TypeError is raised when executing func."""
  168.         self.assertRaises(func, args, None, TypeError, expected_message)
  169.  
  170.     def assertHelp(self, parser, expected_help):
  171.         actual_help = parser.format_help()
  172.         if actual_help != expected_help:
  173.             raise self.failureException(
  174.                 'help text failure; expected:\n"' +
  175.                 expected_help + '"; got:\n"' +
  176.                 actual_help + '"\n')
  177.  
  178. # -- Test make_option() aka Option -------------------------------------
  179.  
  180. # It's not necessary to test correct options here.  All the tests in the
  181. # parser.parse_args() section deal with those, because they're needed
  182. # there.
  183.  
  184. class TestOptionChecks(BaseTest):
  185.     def setUp(self):
  186.         self.parser = OptionParser(usage=SUPPRESS_USAGE)
  187.  
  188.     def assertOptionError(self, expected_message, args=[], kwargs={}):
  189.         self.assertRaises(make_option, args, kwargs,
  190.                           OptionError, expected_message)
  191.  
  192.     def test_opt_string_empty(self):
  193.         self.assertTypeError(make_option,
  194.                              "at least one option string must be supplied")
  195.  
  196.     def test_opt_string_too_short(self):
  197.         self.assertOptionError(
  198.             "invalid option string 'b': must be at least two characters long",
  199.             ["b"])
  200.  
  201.     def test_opt_string_short_invalid(self):
  202.         self.assertOptionError(
  203.             "invalid short option string '--': must be "
  204.             "of the form -x, (x any non-dash char)",
  205.             ["--"])
  206.  
  207.     def test_opt_string_long_invalid(self):
  208.         self.assertOptionError(
  209.             "invalid long option string '---': "
  210.             "must start with --, followed by non-dash",
  211.             ["---"])
  212.  
  213.     def test_attr_invalid(self):
  214.         self.assertOptionError(
  215.             "option -b: invalid keyword arguments: foo, bar",
  216.             ["-b"], {'foo': None, 'bar': None})
  217.  
  218.     def test_action_invalid(self):
  219.         self.assertOptionError(
  220.             "option -b: invalid action: 'foo'",
  221.             ["-b"], {'action': 'foo'})
  222.  
  223.     def test_type_invalid(self):
  224.         self.assertOptionError(
  225.             "option -b: invalid option type: 'foo'",
  226.             ["-b"], {'type': 'foo'})
  227.         self.assertOptionError(
  228.             "option -b: invalid option type: 'tuple'",
  229.             ["-b"], {'type': tuple})
  230.  
  231.     def test_no_type_for_action(self):
  232.         self.assertOptionError(
  233.             "option -b: must not supply a type for action 'count'",
  234.             ["-b"], {'action': 'count', 'type': 'int'})
  235.  
  236.     def test_no_choices_list(self):
  237.         self.assertOptionError(
  238.             "option -b/--bad: must supply a list of "
  239.             "choices for type 'choice'",
  240.             ["-b", "--bad"], {'type': "choice"})
  241.  
  242.     def test_bad_choices_list(self):
  243.         typename = type('').__name__
  244.         self.assertOptionError(
  245.             "option -b/--bad: choices must be a list of "
  246.             "strings ('%s' supplied)" % typename,
  247.             ["-b", "--bad"],
  248.             {'type': "choice", 'choices':"bad choices"})
  249.  
  250.     def test_no_choices_for_type(self):
  251.         self.assertOptionError(
  252.             "option -b: must not supply choices for type 'int'",
  253.             ["-b"], {'type': 'int', 'choices':"bad"})
  254.  
  255.     def test_no_const_for_action(self):
  256.         self.assertOptionError(
  257.             "option -b: 'const' must not be supplied for action 'store'",
  258.             ["-b"], {'action': 'store', 'const': 1})
  259.  
  260.     def test_no_nargs_for_action(self):
  261.         self.assertOptionError(
  262.             "option -b: 'nargs' must not be supplied for action 'count'",
  263.             ["-b"], {'action': 'count', 'nargs': 2})
  264.  
  265.     def test_callback_not_callable(self):
  266.         self.assertOptionError(
  267.             "option -b: callback not callable: 'foo'",
  268.             ["-b"], {'action': 'callback',
  269.                      'callback': 'foo'})
  270.  
  271.     def dummy(self):
  272.         pass
  273.  
  274.     def test_callback_args_no_tuple(self):
  275.         self.assertOptionError(
  276.             "option -b: callback_args, if supplied, "
  277.             "must be a tuple: not 'foo'",
  278.             ["-b"], {'action': 'callback',
  279.                      'callback': self.dummy,
  280.                      'callback_args': 'foo'})
  281.  
  282.     def test_callback_kwargs_no_dict(self):
  283.         self.assertOptionError(
  284.             "option -b: callback_kwargs, if supplied, "
  285.             "must be a dict: not 'foo'",
  286.             ["-b"], {'action': 'callback',
  287.                      'callback': self.dummy,
  288.                      'callback_kwargs': 'foo'})
  289.  
  290.     def test_no_callback_for_action(self):
  291.         self.assertOptionError(
  292.             "option -b: callback supplied ('foo') for non-callback option",
  293.             ["-b"], {'action': 'store',
  294.                      'callback': 'foo'})
  295.  
  296.     def test_no_callback_args_for_action(self):
  297.         self.assertOptionError(
  298.             "option -b: callback_args supplied for non-callback option",
  299.             ["-b"], {'action': 'store',
  300.                      'callback_args': 'foo'})
  301.  
  302.     def test_no_callback_kwargs_for_action(self):
  303.         self.assertOptionError(
  304.             "option -b: callback_kwargs supplied for non-callback option",
  305.             ["-b"], {'action': 'store',
  306.                      'callback_kwargs': 'foo'})
  307.  
  308. class TestOptionParser(BaseTest):
  309.     def setUp(self):
  310.         self.parser = OptionParser()
  311.         self.parser.add_option("-v", "--verbose", "-n", "--noisy",
  312.                           action="store_true", dest="verbose")
  313.         self.parser.add_option("-q", "--quiet", "--silent",
  314.                           action="store_false", dest="verbose")
  315.  
  316.     def test_add_option_no_Option(self):
  317.         self.assertTypeError(self.parser.add_option,
  318.                              "not an Option instance: None", None)
  319.  
  320.     def test_add_option_invalid_arguments(self):
  321.         self.assertTypeError(self.parser.add_option,
  322.                              "invalid arguments", None, None)
  323.  
  324.     def test_get_option(self):
  325.         opt1 = self.parser.get_option("-v")
  326.         self.assert_(isinstance(opt1, Option))
  327.         self.assertEqual(opt1._short_opts, ["-v", "-n"])
  328.         self.assertEqual(opt1._long_opts, ["--verbose", "--noisy"])
  329.         self.assertEqual(opt1.action, "store_true")
  330.         self.assertEqual(opt1.dest, "verbose")
  331.  
  332.     def test_get_option_equals(self):
  333.         opt1 = self.parser.get_option("-v")
  334.         opt2 = self.parser.get_option("--verbose")
  335.         opt3 = self.parser.get_option("-n")
  336.         opt4 = self.parser.get_option("--noisy")
  337.         self.assert_(opt1 is opt2 is opt3 is opt4)
  338.  
  339.     def test_has_option(self):
  340.         self.assert_(self.parser.has_option("-v"))
  341.         self.assert_(self.parser.has_option("--verbose"))
  342.  
  343.     def assert_removed(self):
  344.         self.assert_(self.parser.get_option("-v") is None)
  345.         self.assert_(self.parser.get_option("--verbose") is None)
  346.         self.assert_(self.parser.get_option("-n") is None)
  347.         self.assert_(self.parser.get_option("--noisy") is None)
  348.  
  349.         self.failIf(self.parser.has_option("-v"))
  350.         self.failIf(self.parser.has_option("--verbose"))
  351.         self.failIf(self.parser.has_option("-n"))
  352.         self.failIf(self.parser.has_option("--noisy"))
  353.  
  354.         self.assert_(self.parser.has_option("-q"))
  355.         self.assert_(self.parser.has_option("--silent"))
  356.  
  357.     def test_remove_short_opt(self):
  358.         self.parser.remove_option("-n")
  359.         self.assert_removed()
  360.  
  361.     def test_remove_long_opt(self):
  362.         self.parser.remove_option("--verbose")
  363.         self.assert_removed()
  364.  
  365.     def test_remove_nonexistent(self):
  366.         self.assertRaises(self.parser.remove_option, ('foo',), None,
  367.                           ValueError, "no such option 'foo'")
  368.  
  369. class TestOptionValues(BaseTest):
  370.     def setUp(self):
  371.         pass
  372.  
  373.     def test_basics(self):
  374.         values = Values()
  375.         self.assertEqual(vars(values), {})
  376.         self.assertEqual(values, {})
  377.         self.assertNotEqual(values, {"foo": "bar"})
  378.         self.assertNotEqual(values, "")
  379.  
  380.         dict = {"foo": "bar", "baz": 42}
  381.         values = Values(defaults=dict)
  382.         self.assertEqual(vars(values), dict)
  383.         self.assertEqual(values, dict)
  384.         self.assertNotEqual(values, {"foo": "bar"})
  385.         self.assertNotEqual(values, {})
  386.         self.assertNotEqual(values, "")
  387.         self.assertNotEqual(values, [])
  388.  
  389.  
  390. class TestTypeAliases(BaseTest):
  391.     def setUp(self):
  392.         self.parser = OptionParser()
  393.  
  394.     def test_type_aliases(self):
  395.         self.parser.add_option("-x", type=int)
  396.         self.parser.add_option("-s", type=str)
  397.         self.parser.add_option("-t", type="str")
  398.         self.assertEquals(self.parser.get_option("-x").type, "int")
  399.         self.assertEquals(self.parser.get_option("-s").type, "string")
  400.         self.assertEquals(self.parser.get_option("-t").type, "string")
  401.  
  402.  
  403. # Custom type for testing processing of default values.
  404. _time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 }
  405.  
  406. def _check_duration(option, opt, value):
  407.     try:
  408.         if value[-1].isdigit():
  409.             return int(value)
  410.         else:
  411.             return int(value[:-1]) * _time_units[value[-1]]
  412.     except ValueError, IndexError:
  413.         raise OptionValueError(
  414.             'option %s: invalid duration: %r' % (opt, value))
  415.  
  416. class DurationOption(Option):
  417.     TYPES = Option.TYPES + ('duration',)
  418.     TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
  419.     TYPE_CHECKER['duration'] = _check_duration
  420.  
  421. class TestDefaultValues(BaseTest):
  422.     def setUp(self):
  423.         self.parser = OptionParser()
  424.         self.parser.add_option("-v", "--verbose", default=True)
  425.         self.parser.add_option("-q", "--quiet", dest='verbose')
  426.         self.parser.add_option("-n", type="int", default=37)
  427.         self.parser.add_option("-m", type="int")
  428.         self.parser.add_option("-s", default="foo")
  429.         self.parser.add_option("-t")
  430.         self.parser.add_option("-u", default=None)
  431.         self.expected = { 'verbose': True,
  432.                           'n': 37,
  433.                           'm': None,
  434.                           's': "foo",
  435.                           't': None,
  436.                           'u': None }
  437.  
  438.     def test_basic_defaults(self):
  439.         self.assertEqual(self.parser.get_default_values(), self.expected)
  440.  
  441.     def test_mixed_defaults_post(self):
  442.         self.parser.set_defaults(n=42, m=-100)
  443.         self.expected.update({'n': 42, 'm': -100})
  444.         self.assertEqual(self.parser.get_default_values(), self.expected)
  445.  
  446.     def test_mixed_defaults_pre(self):
  447.         self.parser.set_defaults(x="barf", y="blah")
  448.         self.parser.add_option("-x", default="frob")
  449.         self.parser.add_option("-y")
  450.  
  451.         self.expected.update({'x': "frob", 'y': "blah"})
  452.         self.assertEqual(self.parser.get_default_values(), self.expected)
  453.  
  454.         self.parser.remove_option("-y")
  455.         self.parser.add_option("-y", default=None)
  456.         self.expected.update({'y': None})
  457.         self.assertEqual(self.parser.get_default_values(), self.expected)
  458.  
  459.     def test_process_default(self):
  460.         self.parser.option_class = DurationOption
  461.         self.parser.add_option("-d", type="duration", default=300)
  462.         self.parser.add_option("-e", type="duration", default="6m")
  463.         self.parser.set_defaults(n="42")
  464.         self.expected.update({'d': 300, 'e': 360, 'n': 42})
  465.         self.assertEqual(self.parser.get_default_values(), self.expected)
  466.  
  467.         self.parser.set_process_default_values(False)
  468.         self.expected.update({'d': 300, 'e': "6m", 'n': "42"})
  469.         self.assertEqual(self.parser.get_default_values(), self.expected)
  470.  
  471.  
  472. class TestProgName(BaseTest):
  473.     """
  474.     Test that %prog expands to the right thing in usage, version,
  475.     and help strings.
  476.     """
  477.  
  478.     def assertUsage(self, parser, expected_usage):
  479.         self.assertEqual(parser.get_usage(), expected_usage)
  480.  
  481.     def assertVersion(self, parser, expected_version):
  482.         self.assertEqual(parser.get_version(), expected_version)
  483.  
  484.  
  485.     def test_default_progname(self):
  486.         # Make sure that program name taken from sys.argv[0] by default.
  487.         save_argv = sys.argv[:]
  488.         try:
  489.             sys.argv[0] = os.path.join("foo", "bar", "baz.py")
  490.             parser = OptionParser("usage: %prog ...", version="%prog 1.2")
  491.             expected_usage = "usage: baz.py ...\n"
  492.             self.assertUsage(parser, expected_usage)
  493.             self.assertVersion(parser, "baz.py 1.2")
  494.             self.assertHelp(parser,
  495.                             expected_usage + "\n" +
  496.                             "options:\n"
  497.                             "  --version   show program's version number and exit\n"
  498.                             "  -h, --help  show this help message and exit\n")
  499.         finally:
  500.             sys.argv[:] = save_argv
  501.  
  502.     def test_custom_progname(self):
  503.         parser = OptionParser(prog="thingy",
  504.                               version="%prog 0.1",
  505.                               usage="%prog arg arg")
  506.         parser.remove_option("-h")
  507.         parser.remove_option("--version")
  508.         expected_usage = "usage: thingy arg arg\n"
  509.         self.assertUsage(parser, expected_usage)
  510.         self.assertVersion(parser, "thingy 0.1")
  511.         self.assertHelp(parser, expected_usage + "\n")
  512.  
  513.  
  514. class TestExpandDefaults(BaseTest):
  515.     def setUp(self):
  516.         self.parser = OptionParser(prog="test")
  517.         self.help_prefix = """\
  518. usage: test [options]
  519.  
  520. options:
  521.   -h, --help            show this help message and exit
  522. """
  523.         self.file_help = "read from FILE [default: %default]"
  524.         self.expected_help_file = self.help_prefix + \
  525.             "  -f FILE, --file=FILE  read from FILE [default: foo.txt]\n"
  526.         self.expected_help_none = self.help_prefix + \
  527.             "  -f FILE, --file=FILE  read from FILE [default: none]\n"
  528.  
  529.     def test_option_default(self):
  530.         self.parser.add_option("-f", "--file",
  531.                                default="foo.txt",
  532.                                help=self.file_help)
  533.         self.assertHelp(self.parser, self.expected_help_file)
  534.  
  535.     def test_parser_default_1(self):
  536.         self.parser.add_option("-f", "--file",
  537.                                help=self.file_help)
  538.         self.parser.set_default('file', "foo.txt")
  539.         self.assertHelp(self.parser, self.expected_help_file)
  540.  
  541.     def test_parser_default_2(self):
  542.         self.parser.add_option("-f", "--file",
  543.                                help=self.file_help)
  544.         self.parser.set_defaults(file="foo.txt")
  545.         self.assertHelp(self.parser, self.expected_help_file)
  546.  
  547.     def test_no_default(self):
  548.         self.parser.add_option("-f", "--file",
  549.                                help=self.file_help)
  550.         self.assertHelp(self.parser, self.expected_help_none)
  551.  
  552.     def test_default_none_1(self):
  553.         self.parser.add_option("-f", "--file",
  554.                                default=None,
  555.                                help=self.file_help)
  556.         self.assertHelp(self.parser, self.expected_help_none)
  557.  
  558.     def test_default_none_2(self):
  559.         self.parser.add_option("-f", "--file",
  560.                                help=self.file_help)
  561.         self.parser.set_defaults(file=None)
  562.         self.assertHelp(self.parser, self.expected_help_none)
  563.  
  564.     def test_float_default(self):
  565.         self.parser.add_option(
  566.             "-p", "--prob",
  567.             help="blow up with probability PROB [default: %default]")
  568.         self.parser.set_defaults(prob=0.43)
  569.         expected_help = self.help_prefix + \
  570.             "  -p PROB, --prob=PROB  blow up with probability PROB [default: 0.43]\n"
  571.         self.assertHelp(self.parser, expected_help)
  572.  
  573.     def test_alt_expand(self):
  574.         self.parser.add_option("-f", "--file",
  575.                                default="foo.txt",
  576.                                help="read from FILE [default: *DEFAULT*]")
  577.         self.parser.formatter.default_tag = "*DEFAULT*"
  578.         self.assertHelp(self.parser, self.expected_help_file)
  579.  
  580.     def test_no_expand(self):
  581.         self.parser.add_option("-f", "--file",
  582.                                default="foo.txt",
  583.                                help="read from %default file")
  584.         self.parser.formatter.default_tag = None
  585.         expected_help = self.help_prefix + \
  586.             "  -f FILE, --file=FILE  read from %default file\n"
  587.         self.assertHelp(self.parser, expected_help)
  588.  
  589.  
  590. # -- Test parser.parse_args() ------------------------------------------
  591.  
  592. class TestStandard(BaseTest):
  593.     def setUp(self):
  594.         options = [make_option("-a", type="string"),
  595.                    make_option("-b", "--boo", type="int", dest='boo'),
  596.                    make_option("--foo", action="append")]
  597.  
  598.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  599.                                                option_list=options)
  600.  
  601.     def test_required_value(self):
  602.         self.assertParseFail(["-a"], "-a option requires an argument")
  603.  
  604.     def test_invalid_integer(self):
  605.         self.assertParseFail(["-b", "5x"],
  606.                              "option -b: invalid integer value: '5x'")
  607.  
  608.     def test_no_such_option(self):
  609.         self.assertParseFail(["--boo13"], "no such option: --boo13")
  610.  
  611.     def test_long_invalid_integer(self):
  612.         self.assertParseFail(["--boo=x5"],
  613.                              "option --boo: invalid integer value: 'x5'")
  614.  
  615.     def test_empty(self):
  616.         self.assertParseOK([], {'a': None, 'boo': None, 'foo': None}, [])
  617.  
  618.     def test_shortopt_empty_longopt_append(self):
  619.         self.assertParseOK(["-a", "", "--foo=blah", "--foo="],
  620.                            {'a': "", 'boo': None, 'foo': ["blah", ""]},
  621.                            [])
  622.  
  623.     def test_long_option_append(self):
  624.         self.assertParseOK(["--foo", "bar", "--foo", "", "--foo=x"],
  625.                            {'a': None,
  626.                             'boo': None,
  627.                             'foo': ["bar", "", "x"]},
  628.                            [])
  629.  
  630.     def test_option_argument_joined(self):
  631.         self.assertParseOK(["-abc"],
  632.                            {'a': "bc", 'boo': None, 'foo': None},
  633.                            [])
  634.  
  635.     def test_option_argument_split(self):
  636.         self.assertParseOK(["-a", "34"],
  637.                            {'a': "34", 'boo': None, 'foo': None},
  638.                            [])
  639.  
  640.     def test_option_argument_joined_integer(self):
  641.         self.assertParseOK(["-b34"],
  642.                            {'a': None, 'boo': 34, 'foo': None},
  643.                            [])
  644.  
  645.     def test_option_argument_split_negative_integer(self):
  646.         self.assertParseOK(["-b", "-5"],
  647.                            {'a': None, 'boo': -5, 'foo': None},
  648.                            [])
  649.  
  650.     def test_long_option_argument_joined(self):
  651.         self.assertParseOK(["--boo=13"],
  652.                            {'a': None, 'boo': 13, 'foo': None},
  653.                            [])
  654.  
  655.     def test_long_option_argument_split(self):
  656.         self.assertParseOK(["--boo", "111"],
  657.                            {'a': None, 'boo': 111, 'foo': None},
  658.                            [])
  659.  
  660.     def test_long_option_short_option(self):
  661.         self.assertParseOK(["--foo=bar", "-axyz"],
  662.                            {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
  663.                            [])
  664.  
  665.     def test_abbrev_long_option(self):
  666.         self.assertParseOK(["--f=bar", "-axyz"],
  667.                            {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
  668.                            [])
  669.  
  670.     def test_defaults(self):
  671.         (options, args) = self.parser.parse_args([])
  672.         defaults = self.parser.get_default_values()
  673.         self.assertEqual(vars(defaults), vars(options))
  674.  
  675.     def test_ambiguous_option(self):
  676.         self.parser.add_option("--foz", action="store",
  677.                                type="string", dest="foo")
  678.         possibilities = ", ".join({"--foz": None, "--foo": None}.keys())
  679.         self.assertParseFail(["--f=bar"],
  680.                              "ambiguous option: --f (%s?)" % possibilities)
  681.  
  682.  
  683.     def test_short_and_long_option_split(self):
  684.         self.assertParseOK(["-a", "xyz", "--foo", "bar"],
  685.                            {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
  686.                            []),
  687.  
  688.     def test_short_option_split_long_option_append(self):
  689.         self.assertParseOK(["--foo=bar", "-b", "123", "--foo", "baz"],
  690.                            {'a': None, 'boo': 123, 'foo': ["bar", "baz"]},
  691.                            [])
  692.  
  693.     def test_short_option_split_one_positional_arg(self):
  694.         self.assertParseOK(["-a", "foo", "bar"],
  695.                            {'a': "foo", 'boo': None, 'foo': None},
  696.                            ["bar"]),
  697.  
  698.     def test_short_option_consumes_separator(self):
  699.         self.assertParseOK(["-a", "--", "foo", "bar"],
  700.                            {'a': "--", 'boo': None, 'foo': None},
  701.                            ["foo", "bar"]),
  702.  
  703.     def test_short_option_joined_and_separator(self):
  704.         self.assertParseOK(["-ab", "--", "--foo", "bar"],
  705.                            {'a': "b", 'boo': None, 'foo': None},
  706.                            ["--foo", "bar"]),
  707.  
  708.     def test_invalid_option_becomes_positional_arg(self):
  709.         self.assertParseOK(["-ab", "-", "--foo", "bar"],
  710.                            {'a': "b", 'boo': None, 'foo': ["bar"]},
  711.                            ["-"])
  712.  
  713.     def test_no_append_versus_append(self):
  714.         self.assertParseOK(["-b3", "-b", "5", "--foo=bar", "--foo", "baz"],
  715.                            {'a': None, 'boo': 5, 'foo': ["bar", "baz"]},
  716.                            [])
  717.  
  718.     def test_option_consumes_optionlike_string(self):
  719.         self.assertParseOK(["-a", "-b3"],
  720.                            {'a': "-b3", 'boo': None, 'foo': None},
  721.                            [])
  722.  
  723. class TestBool(BaseTest):
  724.     def setUp(self):
  725.         options = [make_option("-v",
  726.                                "--verbose",
  727.                                action="store_true",
  728.                                dest="verbose",
  729.                                default=''),
  730.                    make_option("-q",
  731.                                "--quiet",
  732.                                action="store_false",
  733.                                dest="verbose")]
  734.         self.parser = OptionParser(option_list = options)
  735.  
  736.     def test_bool_default(self):
  737.         self.assertParseOK([],
  738.                            {'verbose': ''},
  739.                            [])
  740.  
  741.     def test_bool_false(self):
  742.         (options, args) = self.assertParseOK(["-q"],
  743.                                              {'verbose': 0},
  744.                                              [])
  745.         if hasattr(__builtins__, 'False'):
  746.             self.failUnless(options.verbose is False)
  747.  
  748.     def test_bool_true(self):
  749.         (options, args) = self.assertParseOK(["-v"],
  750.                                              {'verbose': 1},
  751.                                              [])
  752.         if hasattr(__builtins__, 'True'):
  753.             self.failUnless(options.verbose is True)
  754.  
  755.     def test_bool_flicker_on_and_off(self):
  756.         self.assertParseOK(["-qvq", "-q", "-v"],
  757.                            {'verbose': 1},
  758.                            [])
  759.  
  760. class TestChoice(BaseTest):
  761.     def setUp(self):
  762.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  763.         self.parser.add_option("-c", action="store", type="choice",
  764.                                dest="choice", choices=["one", "two", "three"])
  765.  
  766.     def test_valid_choice(self):
  767.         self.assertParseOK(["-c", "one", "xyz"],
  768.                            {'choice': 'one'},
  769.                            ["xyz"])
  770.  
  771.     def test_invalid_choice(self):
  772.         self.assertParseFail(["-c", "four", "abc"],
  773.                              "option -c: invalid choice: 'four' "
  774.                              "(choose from 'one', 'two', 'three')")
  775.  
  776.     def test_add_choice_option(self):
  777.         self.parser.add_option("-d", "--default",
  778.                                choices=["four", "five", "six"])
  779.         opt = self.parser.get_option("-d")
  780.         self.assertEqual(opt.type, "choice")
  781.         self.assertEqual(opt.action, "store")
  782.  
  783. class TestCount(BaseTest):
  784.     def setUp(self):
  785.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  786.         self.v_opt = make_option("-v", action="count", dest="verbose")
  787.         self.parser.add_option(self.v_opt)
  788.         self.parser.add_option("--verbose", type="int", dest="verbose")
  789.         self.parser.add_option("-q", "--quiet",
  790.                                action="store_const", dest="verbose", const=0)
  791.  
  792.     def test_empty(self):
  793.         self.assertParseOK([], {'verbose': None}, [])
  794.  
  795.     def test_count_one(self):
  796.         self.assertParseOK(["-v"], {'verbose': 1}, [])
  797.  
  798.     def test_count_three(self):
  799.         self.assertParseOK(["-vvv"], {'verbose': 3}, [])
  800.  
  801.     def test_count_three_apart(self):
  802.         self.assertParseOK(["-v", "-v", "-v"], {'verbose': 3}, [])
  803.  
  804.     def test_count_override_amount(self):
  805.         self.assertParseOK(["-vvv", "--verbose=2"], {'verbose': 2}, [])
  806.  
  807.     def test_count_override_quiet(self):
  808.         self.assertParseOK(["-vvv", "--verbose=2", "-q"], {'verbose': 0}, [])
  809.  
  810.     def test_count_overriding(self):
  811.         self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],
  812.                            {'verbose': 1}, [])
  813.  
  814.     def test_count_interspersed_args(self):
  815.         self.assertParseOK(["--quiet", "3", "-v"],
  816.                            {'verbose': 1},
  817.                            ["3"])
  818.  
  819.     def test_count_no_interspersed_args(self):
  820.         self.parser.disable_interspersed_args()
  821.         self.assertParseOK(["--quiet", "3", "-v"],
  822.                            {'verbose': 0},
  823.                            ["3", "-v"])
  824.  
  825.     def test_count_no_such_option(self):
  826.         self.assertParseFail(["-q3", "-v"], "no such option: -3")
  827.  
  828.     def test_count_option_no_value(self):
  829.         self.assertParseFail(["--quiet=3", "-v"],
  830.                              "--quiet option does not take a value")
  831.  
  832.     def test_count_with_default(self):
  833.         self.parser.set_default('verbose', 0)
  834.         self.assertParseOK([], {'verbose':0}, [])
  835.  
  836.     def test_count_overriding_default(self):
  837.         self.parser.set_default('verbose', 0)
  838.         self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],
  839.                            {'verbose': 1}, [])
  840.  
  841. class TestMultipleArgs(BaseTest):
  842.     def setUp(self):
  843.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  844.         self.parser.add_option("-p", "--point",
  845.                                action="store", nargs=3, type="float", dest="point")
  846.  
  847.     def test_nargs_with_positional_args(self):
  848.         self.assertParseOK(["foo", "-p", "1", "2.5", "-4.3", "xyz"],
  849.                            {'point': (1.0, 2.5, -4.3)},
  850.                            ["foo", "xyz"])
  851.  
  852.     def test_nargs_long_opt(self):
  853.         self.assertParseOK(["--point", "-1", "2.5", "-0", "xyz"],
  854.                            {'point': (-1.0, 2.5, -0.0)},
  855.                            ["xyz"])
  856.  
  857.     def test_nargs_invalid_float_value(self):
  858.         self.assertParseFail(["-p", "1.0", "2x", "3.5"],
  859.                              "option -p: "
  860.                              "invalid floating-point value: '2x'")
  861.  
  862.     def test_nargs_required_values(self):
  863.         self.assertParseFail(["--point", "1.0", "3.5"],
  864.                              "--point option requires 3 arguments")
  865.  
  866. class TestMultipleArgsAppend(BaseTest):
  867.     def setUp(self):
  868.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  869.         self.parser.add_option("-p", "--point", action="store", nargs=3,
  870.                                type="float", dest="point")
  871.         self.parser.add_option("-f", "--foo", action="append", nargs=2,
  872.                                type="int", dest="foo")
  873.  
  874.     def test_nargs_append(self):
  875.         self.assertParseOK(["-f", "4", "-3", "blah", "--foo", "1", "666"],
  876.                            {'point': None, 'foo': [(4, -3), (1, 666)]},
  877.                            ["blah"])
  878.  
  879.     def test_nargs_append_required_values(self):
  880.         self.assertParseFail(["-f4,3"],
  881.                              "-f option requires 2 arguments")
  882.  
  883.     def test_nargs_append_simple(self):
  884.         self.assertParseOK(["--foo=3", "4"],
  885.                            {'point': None, 'foo':[(3, 4)]},
  886.                            [])
  887.  
  888. class TestVersion(BaseTest):
  889.     def test_version(self):
  890.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  891.                                                version="%prog 0.1")
  892.         save_argv = sys.argv[:]
  893.         try:
  894.             sys.argv[0] = os.path.join(os.curdir, "foo", "bar")
  895.             self.assertOutput(["--version"], "bar 0.1\n")
  896.         finally:
  897.             sys.argv[:] = save_argv
  898.  
  899.     def test_no_version(self):
  900.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  901.         self.assertParseFail(["--version"],
  902.                              "no such option: --version")
  903.  
  904. # -- Test conflicting default values and parser.parse_args() -----------
  905.  
  906. class TestConflictingDefaults(BaseTest):
  907.     """Conflicting default values: the last one should win."""
  908.     def setUp(self):
  909.         self.parser = OptionParser(option_list=[
  910.             make_option("-v", action="store_true", dest="verbose", default=1)])
  911.  
  912.     def test_conflict_default(self):
  913.         self.parser.add_option("-q", action="store_false", dest="verbose",
  914.                                default=0)
  915.         self.assertParseOK([], {'verbose': 0}, [])
  916.  
  917.     def test_conflict_default_none(self):
  918.         self.parser.add_option("-q", action="store_false", dest="verbose",
  919.                                default=None)
  920.         self.assertParseOK([], {'verbose': None}, [])
  921.  
  922. class TestOptionGroup(BaseTest):
  923.     def setUp(self):
  924.         self.parser = OptionParser(usage=SUPPRESS_USAGE)
  925.  
  926.     def test_option_group_create_instance(self):
  927.         group = OptionGroup(self.parser, "Spam")
  928.         self.parser.add_option_group(group)
  929.         group.add_option("--spam", action="store_true",
  930.                          help="spam spam spam spam")
  931.         self.assertParseOK(["--spam"], {'spam': 1}, [])
  932.  
  933.     def test_add_group_no_group(self):
  934.         self.assertTypeError(self.parser.add_option_group,
  935.                              "not an OptionGroup instance: None", None)
  936.  
  937.     def test_add_group_invalid_arguments(self):
  938.         self.assertTypeError(self.parser.add_option_group,
  939.                              "invalid arguments", None, None)
  940.  
  941.     def test_add_group_wrong_parser(self):
  942.         group = OptionGroup(self.parser, "Spam")
  943.         group.parser = OptionParser()
  944.         self.assertRaises(self.parser.add_option_group, (group,), None,
  945.                           ValueError, "invalid OptionGroup (wrong parser)")
  946.  
  947.     def test_group_manipulate(self):
  948.         group = self.parser.add_option_group("Group 2",
  949.                                              description="Some more options")
  950.         group.set_title("Bacon")
  951.         group.add_option("--bacon", type="int")
  952.         self.assert_(self.parser.get_option_group("--bacon"), group)
  953.  
  954. # -- Test extending and parser.parse_args() ----------------------------
  955.  
  956. class TestExtendAddTypes(BaseTest):
  957.     def setUp(self):
  958.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  959.                                                option_class=self.MyOption)
  960.         self.parser.add_option("-a", None, type="string", dest="a")
  961.         self.parser.add_option("-f", "--file", type="file", dest="file")
  962.  
  963.     class MyOption (Option):
  964.         def check_file (option, opt, value):
  965.             if not os.path.exists(value):
  966.                 raise OptionValueError("%s: file does not exist" % value)
  967.             elif not os.path.isfile(value):
  968.                 raise OptionValueError("%s: not a regular file" % value)
  969.             return value
  970.  
  971.         TYPES = Option.TYPES + ("file",)
  972.         TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
  973.         TYPE_CHECKER["file"] = check_file
  974.  
  975.     def test_extend_file(self):
  976.         open(test_support.TESTFN, "w").close()
  977.         self.assertParseOK(["--file", test_support.TESTFN, "-afoo"],
  978.                            {'file': test_support.TESTFN, 'a': 'foo'},
  979.                            [])
  980.  
  981.         os.unlink(test_support.TESTFN)
  982.  
  983.     def test_extend_file_nonexistent(self):
  984.         self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
  985.                              "%s: file does not exist" %
  986.                              test_support.TESTFN)
  987.  
  988.     def test_file_irregular(self):
  989.         os.mkdir(test_support.TESTFN)
  990.         self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
  991.                              "%s: not a regular file" %
  992.                              test_support.TESTFN)
  993.         os.rmdir(test_support.TESTFN)
  994.  
  995. class TestExtendAddActions(BaseTest):
  996.     def setUp(self):
  997.         options = [self.MyOption("-a", "--apple", action="extend",
  998.                                  type="string", dest="apple")]
  999.         self.parser = OptionParser(option_list=options)
  1000.  
  1001.     class MyOption (Option):
  1002.         ACTIONS = Option.ACTIONS + ("extend",)
  1003.         STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
  1004.         TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
  1005.  
  1006.         def take_action (self, action, dest, opt, value, values, parser):
  1007.             if action == "extend":
  1008.                 lvalue = value.split(",")
  1009.                 values.ensure_value(dest, []).extend(lvalue)
  1010.             else:
  1011.                 Option.take_action(self, action, dest, opt, parser, value,
  1012.                                    values)
  1013.  
  1014.     def test_extend_add_action(self):
  1015.         self.assertParseOK(["-afoo,bar", "--apple=blah"],
  1016.                            {'apple': ["foo", "bar", "blah"]},
  1017.                            [])
  1018.  
  1019.     def test_extend_add_action_normal(self):
  1020.         self.assertParseOK(["-a", "foo", "-abar", "--apple=x,y"],
  1021.                            {'apple': ["foo", "bar", "x", "y"]},
  1022.                            [])
  1023.  
  1024. # -- Test callbacks and parser.parse_args() ----------------------------
  1025.  
  1026. class TestCallback(BaseTest):
  1027.     def setUp(self):
  1028.         options = [make_option("-x",
  1029.                                None,
  1030.                                action="callback",
  1031.                                callback=self.process_opt),
  1032.                    make_option("-f",
  1033.                                "--file",
  1034.                                action="callback",
  1035.                                callback=self.process_opt,
  1036.                                type="string",
  1037.                                dest="filename")]
  1038.         self.parser = OptionParser(option_list=options)
  1039.  
  1040.     def process_opt(self, option, opt, value, parser_):
  1041.         if opt == "-x":
  1042.             self.assertEqual(option._short_opts, ["-x"])
  1043.             self.assertEqual(option._long_opts, [])
  1044.             self.assert_(parser_ is self.parser)
  1045.             self.assert_(value is None)
  1046.             self.assertEqual(vars(parser_.values), {'filename': None})
  1047.  
  1048.             parser_.values.x = 42
  1049.         elif opt == "--file":
  1050.             self.assertEqual(option._short_opts, ["-f"])
  1051.             self.assertEqual(option._long_opts, ["--file"])
  1052.             self.assert_(parser_ is self.parser)
  1053.             self.assertEqual(value, "foo")
  1054.             self.assertEqual(vars(parser_.values), {'filename': None, 'x': 42})
  1055.  
  1056.             setattr(parser_.values, option.dest, value)
  1057.         else:
  1058.             self.fail("Unknown option %r in process_opt." % opt)
  1059.  
  1060.     def test_callback(self):
  1061.         self.assertParseOK(["-x", "--file=foo"],
  1062.                            {'filename': "foo", 'x': 42},
  1063.                            [])
  1064.  
  1065.     def test_callback_help(self):
  1066.         # This test was prompted by SF bug #960515 -- the point is
  1067.         # not to inspect the help text, just to make sure that
  1068.         # format_help() doesn't crash.
  1069.         parser = OptionParser(usage=SUPPRESS_USAGE)
  1070.         parser.remove_option("-h")
  1071.         parser.add_option("-t", "--test", action="callback",
  1072.                           callback=lambda: None, type="string",
  1073.                           help="foo")
  1074.  
  1075.         expected_help = ("options:\n"
  1076.                          "  -t TEST, --test=TEST  foo\n")
  1077.         self.assertHelp(parser, expected_help)
  1078.  
  1079.  
  1080. class TestCallbackExtraArgs(BaseTest):
  1081.     def setUp(self):
  1082.         options = [make_option("-p", "--point", action="callback",
  1083.                                callback=self.process_tuple,
  1084.                                callback_args=(3, int), type="string",
  1085.                                dest="points", default=[])]
  1086.         self.parser = OptionParser(option_list=options)
  1087.  
  1088.     def process_tuple (self, option, opt, value, parser_, len, type):
  1089.         self.assertEqual(len, 3)
  1090.         self.assert_(type is int)
  1091.  
  1092.         if opt == "-p":
  1093.             self.assertEqual(value, "1,2,3")
  1094.         elif opt == "--point":
  1095.             self.assertEqual(value, "4,5,6")
  1096.  
  1097.         value = tuple(map(type, value.split(",")))
  1098.         getattr(parser_.values, option.dest).append(value)
  1099.  
  1100.     def test_callback_extra_args(self):
  1101.         self.assertParseOK(["-p1,2,3", "--point", "4,5,6"],
  1102.                            {'points': [(1,2,3), (4,5,6)]},
  1103.                            [])
  1104.  
  1105. class TestCallbackMeddleArgs(BaseTest):
  1106.     def setUp(self):
  1107.         options = [make_option(str(x), action="callback",
  1108.                                callback=self.process_n, dest='things')
  1109.                    for x in range(-1, -6, -1)]
  1110.         self.parser = OptionParser(option_list=options)
  1111.  
  1112.     # Callback that meddles in rargs, largs
  1113.     def process_n (self, option, opt, value, parser_):
  1114.         # option is -3, -5, etc.
  1115.         nargs = int(opt[1:])
  1116.         rargs = parser_.rargs
  1117.         if len(rargs) < nargs:
  1118.             self.fail("Expected %d arguments for %s option." % (nargs, opt))
  1119.         dest = parser_.values.ensure_value(option.dest, [])
  1120.         dest.append(tuple(rargs[0:nargs]))
  1121.         parser_.largs.append(nargs)
  1122.         del rargs[0:nargs]
  1123.  
  1124.     def test_callback_meddle_args(self):
  1125.         self.assertParseOK(["-1", "foo", "-3", "bar", "baz", "qux"],
  1126.                            {'things': [("foo",), ("bar", "baz", "qux")]},
  1127.                            [1, 3])
  1128.  
  1129.     def test_callback_meddle_args_separator(self):
  1130.         self.assertParseOK(["-2", "foo", "--"],
  1131.                            {'things': [('foo', '--')]},
  1132.                            [2])
  1133.  
  1134. class TestCallbackManyArgs(BaseTest):
  1135.     def setUp(self):
  1136.         options = [make_option("-a", "--apple", action="callback", nargs=2,
  1137.                                callback=self.process_many, type="string"),
  1138.                    make_option("-b", "--bob", action="callback", nargs=3,
  1139.                                callback=self.process_many, type="int")]
  1140.         self.parser = OptionParser(option_list=options)
  1141.  
  1142.     def process_many (self, option, opt, value, parser_):
  1143.         if opt == "-a":
  1144.             self.assertEqual(value, ("foo", "bar"))
  1145.         elif opt == "--apple":
  1146.             self.assertEqual(value, ("ding", "dong"))
  1147.         elif opt == "-b":
  1148.             self.assertEqual(value, (1, 2, 3))
  1149.         elif opt == "--bob":
  1150.             self.assertEqual(value, (-666, 42, 0))
  1151.  
  1152.     def test_many_args(self):
  1153.         self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong",
  1154.                             "-b", "1", "2", "3", "--bob", "-666", "42",
  1155.                             "0"],
  1156.                            {"apple": None, "bob": None},
  1157.                            [])
  1158.  
  1159. class TestCallbackCheckAbbrev(BaseTest):
  1160.     def setUp(self):
  1161.         self.parser = OptionParser()
  1162.         self.parser.add_option("--foo-bar", action="callback",
  1163.                                callback=self.check_abbrev)
  1164.  
  1165.     def check_abbrev (self, option, opt, value, parser):
  1166.         self.assertEqual(opt, "--foo-bar")
  1167.  
  1168.     def test_abbrev_callback_expansion(self):
  1169.         self.assertParseOK(["--foo"], {}, [])
  1170.  
  1171. class TestCallbackVarArgs(BaseTest):
  1172.     def setUp(self):
  1173.         options = [make_option("-a", type="int", nargs=2, dest="a"),
  1174.                    make_option("-b", action="store_true", dest="b"),
  1175.                    make_option("-c", "--callback", action="callback",
  1176.                                callback=self.variable_args, dest="c")]
  1177.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  1178.                                                option_list=options)
  1179.  
  1180.     def variable_args (self, option, opt, value, parser):
  1181.         self.assert_(value is None)
  1182.         done = 0
  1183.         value = []
  1184.         rargs = parser.rargs
  1185.         while rargs:
  1186.             arg = rargs[0]
  1187.             if ((arg[:2] == "--" and len(arg) > 2) or
  1188.                 (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
  1189.                 break
  1190.             else:
  1191.                 value.append(arg)
  1192.                 del rargs[0]
  1193.         setattr(parser.values, option.dest, value)
  1194.  
  1195.     def test_variable_args(self):
  1196.         self.assertParseOK(["-a3", "-5", "--callback", "foo", "bar"],
  1197.                            {'a': (3, -5), 'b': None, 'c': ["foo", "bar"]},
  1198.                            [])
  1199.  
  1200.     def test_consume_separator_stop_at_option(self):
  1201.         self.assertParseOK(["-c", "37", "--", "xxx", "-b", "hello"],
  1202.                            {'a': None,
  1203.                             'b': True,
  1204.                             'c': ["37", "--", "xxx"]},
  1205.                            ["hello"])
  1206.  
  1207.     def test_positional_arg_and_variable_args(self):
  1208.         self.assertParseOK(["hello", "-c", "foo", "-", "bar"],
  1209.                            {'a': None,
  1210.                             'b': None,
  1211.                             'c':["foo", "-", "bar"]},
  1212.                            ["hello"])
  1213.  
  1214.     def test_stop_at_option(self):
  1215.         self.assertParseOK(["-c", "foo", "-b"],
  1216.                            {'a': None, 'b': True, 'c': ["foo"]},
  1217.                            [])
  1218.  
  1219.     def test_stop_at_invalid_option(self):
  1220.         self.assertParseFail(["-c", "3", "-5", "-a"], "no such option: -5")
  1221.  
  1222.  
  1223. # -- Test conflict handling and parser.parse_args() --------------------
  1224.  
  1225. class ConflictBase(BaseTest):
  1226.     def setUp(self):
  1227.         options = [make_option("-v", "--verbose", action="count",
  1228.                                dest="verbose", help="increment verbosity")]
  1229.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  1230.                                                option_list=options)
  1231.  
  1232.     def show_version (self, option, opt, value, parser):
  1233.         parser.values.show_version = 1
  1234.  
  1235. class TestConflict(ConflictBase):
  1236.     """Use the default conflict resolution for Optik 1.2: error."""
  1237.     def assert_conflict_error(self, func):
  1238.         err = self.assertRaises(
  1239.             func, ("-v", "--version"), {'action' : "callback",
  1240.                                         'callback' : self.show_version,
  1241.                                         'help' : "show version"},
  1242.             OptionConflictError,
  1243.             "option -v/--version: conflicting option string(s): -v")
  1244.  
  1245.         self.assertEqual(err.msg, "conflicting option string(s): -v")
  1246.         self.assertEqual(err.option_id, "-v/--version")
  1247.  
  1248.     def test_conflict_error(self):
  1249.         self.assert_conflict_error(self.parser.add_option)
  1250.  
  1251.     def test_conflict_error_group(self):
  1252.         group = OptionGroup(self.parser, "Group 1")
  1253.         self.assert_conflict_error(group.add_option)
  1254.  
  1255.     def test_no_such_conflict_handler(self):
  1256.         self.assertRaises(
  1257.             self.parser.set_conflict_handler, ('foo',), None,
  1258.             ValueError, "invalid conflict_resolution value 'foo'")
  1259.  
  1260.  
  1261. class TestConflictResolve(ConflictBase):
  1262.     def setUp(self):
  1263.         ConflictBase.setUp(self)
  1264.         self.parser.set_conflict_handler("resolve")
  1265.         self.parser.add_option("-v", "--version", action="callback",
  1266.                                callback=self.show_version, help="show version")
  1267.  
  1268.     def test_conflict_resolve(self):
  1269.         v_opt = self.parser.get_option("-v")
  1270.         verbose_opt = self.parser.get_option("--verbose")
  1271.         version_opt = self.parser.get_option("--version")
  1272.  
  1273.         self.assert_(v_opt is version_opt)
  1274.         self.assert_(v_opt is not verbose_opt)
  1275.         self.assertEqual(v_opt._long_opts, ["--version"])
  1276.         self.assertEqual(version_opt._short_opts, ["-v"])
  1277.         self.assertEqual(version_opt._long_opts, ["--version"])
  1278.         self.assertEqual(verbose_opt._short_opts, [])
  1279.         self.assertEqual(verbose_opt._long_opts, ["--verbose"])
  1280.  
  1281.     def test_conflict_resolve_help(self):
  1282.         self.assertOutput(["-h"], """\
  1283. options:
  1284.   --verbose      increment verbosity
  1285.   -h, --help     show this help message and exit
  1286.   -v, --version  show version
  1287. """)
  1288.  
  1289.     def test_conflict_resolve_short_opt(self):
  1290.         self.assertParseOK(["-v"],
  1291.                            {'verbose': None, 'show_version': 1},
  1292.                            [])
  1293.  
  1294.     def test_conflict_resolve_long_opt(self):
  1295.         self.assertParseOK(["--verbose"],
  1296.                            {'verbose': 1},
  1297.                            [])
  1298.  
  1299.     def test_conflict_resolve_long_opts(self):
  1300.         self.assertParseOK(["--verbose", "--version"],
  1301.                            {'verbose': 1, 'show_version': 1},
  1302.                            [])
  1303.  
  1304. class TestConflictOverride(BaseTest):
  1305.     def setUp(self):
  1306.         self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  1307.         self.parser.set_conflict_handler("resolve")
  1308.         self.parser.add_option("-n", "--dry-run",
  1309.                                action="store_true", dest="dry_run",
  1310.                                help="don't do anything")
  1311.         self.parser.add_option("--dry-run", "-n",
  1312.                                action="store_const", const=42, dest="dry_run",
  1313.                                help="dry run mode")
  1314.  
  1315.     def test_conflict_override_opts(self):
  1316.         opt = self.parser.get_option("--dry-run")
  1317.         self.assertEqual(opt._short_opts, ["-n"])
  1318.         self.assertEqual(opt._long_opts, ["--dry-run"])
  1319.  
  1320.     def test_conflict_override_help(self):
  1321.         self.assertOutput(["-h"], """\
  1322. options:
  1323.   -h, --help     show this help message and exit
  1324.   -n, --dry-run  dry run mode
  1325. """)
  1326.  
  1327.     def test_conflict_override_args(self):
  1328.         self.assertParseOK(["-n"],
  1329.                            {'dry_run': 42},
  1330.                            [])
  1331.  
  1332. # -- Other testing. ----------------------------------------------------
  1333.  
  1334. _expected_help_basic = """\
  1335. usage: bar.py [options]
  1336.  
  1337. options:
  1338.   -a APPLE           throw APPLEs at basket
  1339.   -b NUM, --boo=NUM  shout "boo!" NUM times (in order to frighten away all the
  1340.                      evil spirits that cause trouble and mayhem)
  1341.   --foo=FOO          store FOO in the foo list for later fooing
  1342.   -h, --help         show this help message and exit
  1343. """
  1344.  
  1345. _expected_help_long_opts_first = """\
  1346. usage: bar.py [options]
  1347.  
  1348. options:
  1349.   -a APPLE           throw APPLEs at basket
  1350.   --boo=NUM, -b NUM  shout "boo!" NUM times (in order to frighten away all the
  1351.                      evil spirits that cause trouble and mayhem)
  1352.   --foo=FOO          store FOO in the foo list for later fooing
  1353.   --help, -h         show this help message and exit
  1354. """
  1355.  
  1356. _expected_help_title_formatter = """\
  1357. Usage
  1358. =====
  1359.   bar.py [options]
  1360.  
  1361. options
  1362. =======
  1363. -a APPLE           throw APPLEs at basket
  1364. --boo=NUM, -b NUM  shout "boo!" NUM times (in order to frighten away all the
  1365.                    evil spirits that cause trouble and mayhem)
  1366. --foo=FOO          store FOO in the foo list for later fooing
  1367. --help, -h         show this help message and exit
  1368. """
  1369.  
  1370. _expected_help_short_lines = """\
  1371. usage: bar.py [options]
  1372.  
  1373. options:
  1374.   -a APPLE           throw APPLEs at basket
  1375.   -b NUM, --boo=NUM  shout "boo!" NUM times (in order to
  1376.                      frighten away all the evil spirits
  1377.                      that cause trouble and mayhem)
  1378.   --foo=FOO          store FOO in the foo list for later
  1379.                      fooing
  1380.   -h, --help         show this help message and exit
  1381. """
  1382.  
  1383. class TestHelp(BaseTest):
  1384.     def setUp(self):
  1385.         self.parser = self.make_parser(80)
  1386.  
  1387.     def make_parser(self, columns):
  1388.         options = [
  1389.             make_option("-a", type="string", dest='a',
  1390.                         metavar="APPLE", help="throw APPLEs at basket"),
  1391.             make_option("-b", "--boo", type="int", dest='boo',
  1392.                         metavar="NUM",
  1393.                         help=
  1394.                         "shout \"boo!\" NUM times (in order to frighten away "
  1395.                         "all the evil spirits that cause trouble and mayhem)"),
  1396.             make_option("--foo", action="append", type="string", dest='foo',
  1397.                         help="store FOO in the foo list for later fooing"),
  1398.             ]
  1399.         os.environ['COLUMNS'] = str(columns)
  1400.         return InterceptingOptionParser(option_list=options)
  1401.  
  1402.     def assertHelpEquals(self, expected_output):
  1403.         save_argv = sys.argv[:]
  1404.         try:
  1405.             # Make optparse believe bar.py is being executed.
  1406.             sys.argv[0] = os.path.join("foo", "bar.py")
  1407.             self.assertOutput(["-h"], expected_output)
  1408.         finally:
  1409.             sys.argv[:] = save_argv
  1410.  
  1411.     def test_help(self):
  1412.         self.assertHelpEquals(_expected_help_basic)
  1413.  
  1414.     def test_help_old_usage(self):
  1415.         self.parser.set_usage("usage: %prog [options]")
  1416.         self.assertHelpEquals(_expected_help_basic)
  1417.  
  1418.     def test_help_long_opts_first(self):
  1419.         self.parser.formatter.short_first = 0
  1420.         self.assertHelpEquals(_expected_help_long_opts_first)
  1421.  
  1422.     def test_help_title_formatter(self):
  1423.         self.parser.formatter = TitledHelpFormatter()
  1424.         self.assertHelpEquals(_expected_help_title_formatter)
  1425.  
  1426.     def test_wrap_columns(self):
  1427.         # Ensure that wrapping respects $COLUMNS environment variable.
  1428.         # Need to reconstruct the parser, since that's the only time
  1429.         # we look at $COLUMNS.
  1430.         self.parser = self.make_parser(60)
  1431.         self.assertHelpEquals(_expected_help_short_lines)
  1432.  
  1433.     def test_help_description_groups(self):
  1434.         self.parser.set_description(
  1435.             "This is the program description for %prog.  %prog has "
  1436.             "an option group as well as single options.")
  1437.  
  1438.         group = OptionGroup(
  1439.             self.parser, "Dangerous Options",
  1440.             "Caution: use of these options is at your own risk.  "
  1441.             "It is believed that some of them bite.")
  1442.         group.add_option("-g", action="store_true", help="Group option.")
  1443.         self.parser.add_option_group(group)
  1444.  
  1445.         self.assertHelpEquals("""\
  1446. usage: bar.py [options]
  1447.  
  1448. This is the program description for bar.py.  bar.py has an option group as
  1449. well as single options.
  1450.  
  1451. options:
  1452.   -a APPLE           throw APPLEs at basket
  1453.   -b NUM, --boo=NUM  shout "boo!" NUM times (in order to frighten away all the
  1454.                      evil spirits that cause trouble and mayhem)
  1455.   --foo=FOO          store FOO in the foo list for later fooing
  1456.   -h, --help         show this help message and exit
  1457.  
  1458.   Dangerous Options:
  1459.     Caution: use of these options is at your own risk.  It is believed
  1460.     that some of them bite.
  1461.  
  1462.     -g               Group option.
  1463. """)
  1464.  
  1465.  
  1466.  
  1467.  
  1468. class TestMatchAbbrev(BaseTest):
  1469.     def test_match_abbrev(self):
  1470.         self.assertEqual(_match_abbrev("--f",
  1471.                                        {"--foz": None,
  1472.                                         "--foo": None,
  1473.                                         "--fie": None,
  1474.                                         "--f": None}),
  1475.                          "--f")
  1476.  
  1477.     def test_match_abbrev_error(self):
  1478.         s = "--f"
  1479.         wordmap = {"--foz": None, "--foo": None, "--fie": None}
  1480.         possibilities = ", ".join(wordmap.keys())
  1481.         self.assertRaises(
  1482.             _match_abbrev, (s, wordmap), None,
  1483.             BadOptionError, "ambiguous option: --f (%s?)" % possibilities)
  1484.  
  1485.  
  1486. def _testclasses():
  1487.     mod = sys.modules[__name__]
  1488.     return [getattr(mod, name) for name in dir(mod) if name.startswith('Test')]
  1489.  
  1490. def suite():
  1491.     suite = unittest.TestSuite()
  1492.     for testclass in _testclasses():
  1493.         suite.addTest(unittest.makeSuite(testclass))
  1494.     return suite
  1495.  
  1496. def test_main():
  1497.     test_support.run_suite(suite())
  1498.  
  1499. if __name__ == '__main__':
  1500.     unittest.main()
  1501.